package com.zkh.myframe.core;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.zkh.myframe.annotation.validate.Custom;
import com.zkh.myframe.annotation.validate.DateRange;
import com.zkh.myframe.annotation.validate.Email;
import com.zkh.myframe.annotation.validate.ExistValue;
import com.zkh.myframe.annotation.validate.Length;
import com.zkh.myframe.annotation.validate.Max;
import com.zkh.myframe.annotation.validate.Min;
import com.zkh.myframe.annotation.validate.NotBlank;
import com.zkh.myframe.annotation.validate.NotEmpty;
import com.zkh.myframe.annotation.validate.NotNull;
import com.zkh.myframe.annotation.validate.Range;
import com.zkh.myframe.annotation.validate.RegExp;
import com.zkh.myframe.validate.DefaultValidator;
import com.zkh.myframe.validate.ParamValidator;
import com.zkh.myutils.annotation.Ignore;
import com.zkh.myutils.bean.BeanUtils;
import com.zkh.myutils.bean.Type;
import com.zkh.myutils.io.log.Logger;
import com.zkh.myutils.utils.DateUtils;
import com.zkh.myutils.utils.StringUtils;
import com.zkh.myutils.utils.Utils;
import com.zkh.myutils.utils.UtilsException;

/**
 * 参数验证器检查类，系统内部调用
 * @author zkh
 */
class ValidatorChecker {

	/**
	 * 参数赋值并执行参数验证器检查（格式化参数值优先级大于原本参数值）。仅供Chain调用。
	 * @param adapter 适配器
	 * @return 返回字段名和错误信息，如果验证通过，返回Map.isEmpty()为true
	 */
	static Map<String, String> execParamValidatorCheck(Adapter<ParamValidator> adapter) {
		//错误信息
		Map<String, String> errorMsgMap = new HashMap<String, String>();
		//验证器对象
		ParamValidator validator;
		//流参数
		if(adapter.isJSONParam()) {
			validator = adapter.getJsonParamToEntity(adapter.getValidatorClass());
		}else {
			//转换
			validator = BeanUtils.parameterToBean(adapter.getParameterMap(), adapter.getValidatorClass());
		}
		//保存验证器值
		adapter.setParamValidator(validator);
		//不是默认验证器
		if(!(validator instanceof DefaultValidator)) {
			//临时Clazz
			Class<?> cls = adapter.getValidatorClass();
			//遍历
			while(cls!=null && !Type.OBJECT.equals(cls.getName())) {
				//获取所有字段
				Field[] fields = cls.getDeclaredFields();
				try {
					//遍历字段
					for(Field field: fields) {
						//是否有忽略注解，不忽略才检查
						if(!field.isAnnotationPresent(Ignore.class)) {
							//获取所有注解
							Annotation[] annos = field.getAnnotations();
							//至少要有一个注解
							if(annos.length>0) {
								//getter
								String getter = "get" + StringUtils.uppercaseFirst(field.getName());
								//获取值
								Object value = cls.getMethod(getter).invoke(validator);
								//检查，返回错误信息
								String errorMsg = execParamCheck(adapter.getValidatorClass(), validator, annos, value);
								//存在错误信息
								if(errorMsg!=null) {
									errorMsgMap.put(field.getName(), errorMsg);
								}
							}
						}
					}
					//父类
					cls = cls.getSuperclass();
				}catch (NoSuchMethodException e) {
					//打印错误日志
					Logger.error(e);
					//抛出运行时异常
					throw new UtilsException("getter不存在：" + e.getMessage());
				}catch (IllegalAccessException e) {
					//打印错误日志
					Logger.error(e);
					//抛出运行时异常
					throw new UtilsException("getter没有访问权限：" + e.getMessage());
				}catch (InvocationTargetException e) {
					throw new UtilsException(e.getTargetException());
				}
			}
		}
		//返回错误信息
		return errorMsgMap;
	}

	/**
	 * 执行参数检查
	 * @param clazz 参数验证器Class，自定义验证规则使用
	 * @param validator 参数验证器，自定义验证规则使用
	 * @param annos 注解列表
	 * @param type 字段类型
	 * @param value 字段值
	 */
	private static String execParamCheck(Class<ParamValidator> clazz, ParamValidator validator, Annotation[] annos, Object value) throws IllegalAccessException, IllegalArgumentException {
		//遍历注解
		for(Annotation anno: annos) {
			//错误信息
			String msg = null;
			//分别判断类型
			if(anno instanceof NotNull) {
				msg = notNullCheck((NotNull) anno, value);
			}else if(anno instanceof NotEmpty) {
				msg = notEmptyCheck((NotEmpty) anno, value);
			}else if(anno instanceof NotBlank) {
				msg = notBlankCheck((NotBlank) anno, value);
			}else if(anno instanceof DateRange) {
				msg = dateRangeCheck((DateRange) anno, value);
			}else if(anno instanceof Email) {
				msg = emailCheck((Email) anno, value);
			}else if(anno instanceof Length) {
				msg = lengthCheck((Length) anno, value);
			}else if(anno instanceof Range) {
				msg = rangeCheck((Range) anno, value);
			}else if(anno instanceof RegExp) {
				msg = regExpCheck((RegExp) anno, value);
			}else if(anno instanceof ExistValue) {
				msg = existValueCheck((ExistValue) anno, value);
			}else if(anno instanceof Max) {
				msg = maxCheck((Max) anno, value);
			}else if(anno instanceof Min) {
				msg = minCheck((Min) anno, value);
			}else if(anno instanceof Custom) {
				//验证规则对象
				Custom custom = (Custom) anno;
				try {
					//方法
					Method method = clazz.getMethod(custom.method());
					//反射调用方法
					Object res = method.invoke(validator);
					//不为空
					if(res!=null) {
						msg = res.toString();
					}
				}catch(NoSuchMethodException e1) {
					msg = "指定的自定义规则验证方法不存在：" + e1.getMessage();
				}catch(InvocationTargetException e2) {
					msg = e2.getTargetException().getMessage();
				}
				
			}
			//有错误信息，返回错误信息，不再检查
			if(msg!=null) {
				return msg;
			}
		}
		return null;
	}
	/**
	 * NotNull检查
	 */
	private static String notNullCheck(NotNull notNull, Object value) {
		return value==null ? notNull.message() : null;
	}
	
	/**
	 * NotEmpty检查<br/>
	 * 字段为null或字符串、集合、Map判isEmpty()，数组判length=0时的错误信息
	 */
	private static String notEmptyCheck(NotEmpty notEmpty, Object value) {
		return Utils.isEmpty(value) ? notEmpty.message() : null;
	}
	
	/**
	 * NotBlank检查<br/>
	 * 字段为null或字符串为空白字符
	 */
	private static String notBlankCheck(NotBlank notBlank, Object value) {
		return value==null || (value instanceof String && StringUtils.isBlank((String) value)) ? notBlank.message() : null;
	}
	
	/**
	 * DateRange检查
	 */
	private static String dateRangeCheck(DateRange dateRange, Object value) {
		if(value instanceof Date) {
			//值
			Date val = (Date) value;
			//最大/小值
			String min = dateRange.min(), max = dateRange.max();
			//长度
			int minL = min==null ? 0 : min.length(), maxL = max==null ? 0 : max.length();
			//当前
			boolean minN = "now".equalsIgnoreCase(min), maxN = "now".equalsIgnoreCase(max);
			//最小值和最小值判断
			if(((minL==8 || minL==14 || minN) && val.before(minN ? new Date() : DateUtils.getDate(min, minL==8 ? "yyyyMMdd" : "yyyyMMddHHmmss"))) 
					|| ((maxL==8 || maxL==14 || maxN) && val.after(maxN ? new Date() : DateUtils.getDate(max, maxL==8 ? "yyyyMMdd" : "yyyyMMddHHmmss")))) {
				return dateRange.message();
			}
		}
		return null;
	}
	
	/**
	 * Email检查
	 */
	private static String emailCheck(Email email, Object value) {
		return !(value instanceof String) || StringUtils.isEmail((String) value) ? null : email.message();
	}
	
	/**
	 * Length检查<br/>
	 * 针对字符串、数组length，集合size
	 */
	private static String lengthCheck(Length length, Object value) {
		if(value!=null) {
			//最大/小值
			int max = length.max(), min = length.min();
			//有值
			if(max>-1 || min>-1) {
				//获取值长度
				int len = value instanceof String ? ((String) value).length() : (value.getClass().isArray() ? Array.getLength(value) : (value instanceof Collection ? ((Collection<?>) value).size() : -1));
				//大于-1
				if(len>-1 && ((min>-1 && len<min) || (max>-1 && len>max))) {
					return length.message();
				}
			}
		}
		return null;
	}
	
	/**
	 * Range检查
	 */
	private static String rangeCheck(Range range, Object value) {
		//是Number类型
		if(value instanceof Number) {
			//获取值
			double v = ((Number) value).doubleValue();
			//不在范围内
			if(v<range.min() || v>range.max()) {
				return range.message();
			}
		}
		return null;
	}

	/**
	 * Max检查
	 */
	private static String maxCheck(Max max, Object value) {
		//是Number类型
		if((value instanceof Number) && ((Number) value).doubleValue()>max.max()) {
			return max.message();
		}
		return null;
	}

	/**
	 * Min检查
	 */
	private static String minCheck(Min min, Object value) {
		//是Number类型
		if((value instanceof Number) && ((Number) value).doubleValue()<min.min()) {
			return min.message();
		}
		return null;
	}
	
	/**
	 * RegExp检查
	 */
	private static String regExpCheck(RegExp regExp, Object value) {
		return (value instanceof String) && !((String) value).matches(regExp.pattern()) ? regExp.message() : null;
	}
	
	/**
	 * 存在某个值的检查
	 */
	private static String existValueCheck(ExistValue existValue, Object value) {
		//有值
		if((value instanceof String) && existValue.candidates().length>0) {
			//当前值
			String val = (String) value;
			//是否存在
			if(!StringUtils.isExist(val, existValue.ignoreCase(), existValue.candidates())) {
				return existValue.message();
			}
		}
		return null;
	}
}
